/* ================================================================================ *//**
 \license     %LICENSE%
 \file        syscalls.c
 \author      Lukasz Krzak
 \purpose     STM32 demo application
 \compiler    %COMPILER%
 \hardware    independent
 \doc         doxygen
 \brief       System calls implementation for newlib
 \comments
*//* ================================================================================= */

#include <stdlib.h>
#include <sys/stat.h>
#include "stm32f10x.h"

#define USART                           USART1
#define USART_TX_PORT                   GPIOA
#define USART_TX_PIN                    GPIO_Pin_9
#define USART_RX_PORT                   GPIOA
#define USART_RX_PIN                    GPIO_Pin_10

static int usart_configured = 0;
int heap_used = 0;

// -----------------------------------------------------------------------------
//  configure_usart
// -----------------------------------------------------------------------------
static void configure_usart(void)
{
    GPIO_InitTypeDef gpio_config;
    USART_InitTypeDef usart_config;

    // Enable GPIOA, USART peripheral clock
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE );

    // Configure USART TX/RX pins
    gpio_config.GPIO_Speed = GPIO_Speed_50MHz;
    gpio_config.GPIO_Pin = USART_TX_PIN;
    gpio_config.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(USART_TX_PORT, &gpio_config);

    gpio_config.GPIO_Pin = USART_RX_PIN;
    gpio_config.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(USART_RX_PORT, &gpio_config);

    /* Initialize USART configured as follow:
                            - BaudRate = 19200 baud
                            - Word Length = 8 Bits
                            - One Stop Bit
                            - No parity
                            - Hardware flow control disabled (RTS and CTS signals)
                            - Receive and transmit enabled
     */
    usart_config.USART_BaudRate = 115200;
    usart_config.USART_WordLength = USART_WordLength_8b;
    usart_config.USART_StopBits = USART_StopBits_1;
    usart_config.USART_Parity = USART_Parity_No;
    usart_config.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    usart_config.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    // Configure USART using the structure above
    USART_Init(USART, &usart_config);

    // Enable USART
    USART_Cmd(USART, ENABLE);

    usart_configured = 1;

} /* configure_usart */

// -----------------------------------------------------------------------------
//  _close
// -----------------------------------------------------------------------------
int _close(int file)
{
    return -1;
} /* _close */


// -----------------------------------------------------------------------------
//  _isatty
// -----------------------------------------------------------------------------
int _isatty(int file)
{
    return 1;

} /* _isatty */


// -----------------------------------------------------------------------------
//  _fstat
// -----------------------------------------------------------------------------
int _fstat(int file, struct stat* st)
{
    st->st_mode = S_IFCHR;

    return 0;

} /* _fstat */


// -----------------------------------------------------------------------------
//  _lseek
// -----------------------------------------------------------------------------
int _lseek(int file, int ptr, int dir)
{
    return 0;

} /* _lseek */


// -----------------------------------------------------------------------------
//  _read
// -----------------------------------------------------------------------------
int _read(int file, char* ptr, int len)
{
    int i;

    if (0 == usart_configured) {
        configure_usart();
    }

    // flush USART data register if needed
    while (USART_GetFlagStatus(USART, USART_FLAG_RXNE) == SET) {
        USART_ReceiveData(USART);
    }

    i = 0;

    while (i < len) {
        // Loop until the USART data register is not empty (that means it has received some data)
        while (USART_GetFlagStatus(USART, USART_FLAG_RXNE) == RESET) {
            ;
        }

        // Read data from USART data register
        *ptr = USART_ReceiveData(USART);

        // Loopback
        USART_SendData(USART, *ptr);

        // Loop until USART data register is empty again (data is sent)
        while (USART_GetFlagStatus(USART, USART_FLAG_TXE) == RESET) {
            ;
        }

        // Increase number of bytes
        i++;

        if ((*ptr == '\r') || (*ptr == '\n')) {
            // end of line detected
            *ptr = '\n';
            return i;
        }

        ptr++;
    }

    return i;
} /* _read */


// -----------------------------------------------------------------------------
//  _write
// -----------------------------------------------------------------------------
int _write(int file, char* ptr, int len)
{
    int i;
    char* string = ptr;

    if (0 == usart_configured) {
        configure_usart();
    }

    if ((len) && (ptr)) {

        // Print message (strlen function returns the number of characters in the message)
        i = 0;

        while (i < len) {
            // Send out a single character
            USART_SendData(USART, *(string++));

            // Loop until USART data register is empty again (data is sent)
            while (USART_GetFlagStatus(USART, USART_FLAG_TXE) == RESET) {
                ;
            }

            i++;
        }
    }

    return len;

} /* _write */


// -----------------------------------------------------------------------------
//  _sbrk
// -----------------------------------------------------------------------------
caddr_t _sbrk(int incr)
{
    extern char _end;       /* Defined by the linker */
    static char* heap_end;
    char* prev_heap_end;

    if (heap_end == 0) {
        heap_end = &_end;
    }

    prev_heap_end = heap_end;

    heap_end += incr;
    heap_used += incr;

    return (caddr_t)prev_heap_end;

} /* _sbrk */

#define __MYPID 1
 int _getpid()
 {
 return __MYPID;
 }

/*
 * kill -- go out via exit...
 */
 int _kill(int pid, int sig)
 {

 return -1;
 }

int _exit(int val)
{
	return (-1);
}
